package com.bid.base.common.util.ssl;

import sun.security.x509.CertificateValidity;
import sun.security.x509.X509CertImpl;
import sun.security.x509.X509CertInfo;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.util.Date;

/**
 * <strong>Description : </strong> <br>
 * <p>
 * <strong>北京正源德标科技信息有限责任公司</strong> <br>
 * </p>
 * <br>
 *
 * @author : zhaots
 * @date Date : 2020年12月28日 10:24
 * 修改人 修改日期 修改描述<br>
 * -------------------------------------------<br>
 *     PKCS12 证书的生成及验证
 *     https://blog.csdn.net/kmyhy/article/details/6431609
 *
 *
 *     Java实现SSL双向认证的方法
 *     socket
 *     https://blog.csdn.net/moonpure/article/details/82836517
 * <br>
 * <br>
 */
public class Pkcs12Manager {

    public File file ;

    public KeyStore keyStore ;

    private char [] storePass ;

    public Pkcs12Manager(File file, String pass) throws IOException, Exception {
        this.file = file;
        this.storePass = pass.toCharArray();
        getKeyStore(); // 加载 KeyStore 文件

    }
    // 加载 KeyStore 文件
    public synchronized KeyStore getKeyStore() throws IOException, Exception {
        if (keyStore == null) {
            FileInputStream fin = new FileInputStream(file);
            KeyStore store = KeyStore.getInstance("PKCS12");
            try {
                store.load(fin, storePass);
            } finally {
                try {
                    fin.close();
                } catch (IOException e) {
                }
            }
            keyStore = store;
        }
        return keyStore;
    }
    // 读取 alias 指定的证书内容
    public X509CertInfo getX509CertInfo(String alias) throws Exception {
        X509CertImpl cimp = getX509CertImpl(alias);
        // 获取 X509CertInfo 对象
        return (X509CertInfo) cimp.get(X509CertImpl.NAME
                + "." + X509CertImpl.INFO);
    }

    // 根据 alias 获取 X509CertImpl 对象
    private X509CertImpl getX509CertImpl(String alias) throws Exception {
        Certificate c = keyStore.getCertificate(alias); // 读取证书
        String type = c.getType();
        // 从待签发的证书中提取证书信息　　
        byte[] enc = c.getEncoded(); // 获取 证书内容（经过编码的字节）
        X509CertImpl cimp = new X509CertImpl(enc); // 创建 X509CertImpl 象
        return cimp;

    }

// 修改证书过期时间 : 过期时间顺延 n 天

    public void updateExpiration(String alias,String keypass, int n) throws Exception {
        X509CertInfo cinfo = getX509CertInfo(alias); // 获取 X509CertInfo 对象
        X509CertImpl cimp = getX509CertImpl(alias); // 获取 X509CertImpl 对象
        String sigAlgrithm = cimp.getSigAlgName(); // 获取签名算法
        CertificateValidity cv = (CertificateValidity) cinfo.get(X509CertInfo.VALIDITY);
        // 有效期为当前日期后延 n 天 xx
        Date d = (Date) cv.get(CertificateValidity.NOT_AFTER);
        Date d2 = new Date(d.getTime() + n * 24 * 60 * 60 * 1000L);
// 创建有效期对象
        cv.set(CertificateValidity.NOT_AFTER, d2);
        cinfo.set(X509CertInfo.VALIDITY, cv); // 设置有效期
        saveCert(alias, keypass, cinfo, sigAlgrithm);
    }
    //  读取证书过期时间
    public String getExpiration(String alias) throws Exception {
        X509CertInfo cinfo = getX509CertInfo(alias);
        CertificateValidity cv = (CertificateValidity) cinfo.get(X509CertInfo.VALIDITY);
        // 创建有效期对象
        Date d = (Date) cv.get(CertificateValidity.NOT_AFTER);
        return d.toString();
    }

//  存储证书
private void saveCert(String alias, String keypass,
                      X509CertInfo cinfo, String algrithm) throws Exception {
// 从密钥库中读取 CA 的私钥
        PrivateKey pKey = (PrivateKey) keyStore.getKey(alias, keypass.toCharArray());
        System.out.println("私钥是： \t" +pKey.toString() + "\t" );
        X509CertImpl cert = new X509CertImpl(cinfo); // 新建证书
        cert.sign(pKey, algrithm); // 使用 CA 私钥对其签名
// 获取别名对应条目的证书链
        Certificate[] chain = new Certificate[]{cert};
// 向密钥库中添加条目 , 使用已存在别名将覆盖已存在条目
        keyStore.setKeyEntry(alias, pKey, keypass.toCharArray(), chain);
// 将 keystore 存储至文件
        FileOutputStream fOut = new FileOutputStream(file);
        keyStore.store(fOut, storePass);
        fOut.close();
    }

// 获取签名算法

    public String getSigAlgName(String alias) throws Exception {

        Certificate c = keyStore.getCertificate(alias); // 读取证书

// 获取 证书内容（经过编码的字节）　　

        byte[] enc = c.getEncoded();

// 创建 X509CertImpl 对象

        X509CertImpl cimp2 = new X509CertImpl(enc);

        String sigAlgrithm = cimp2.getSigAlgName();

        return sigAlgrithm;

    }

    public static void main(String[] args) throws Exception {
        System.out.println("start");
//        String filename= "D:\\ZYDB\\code\\p12.cer" ; dlt.p12
        String filename = "D:\\ZYDB\\code\\dlt.p12";
        String pass = "ipcc@95598";
        Pkcs12Manager man = null;
        String alias = "p12client";
        String keypass = "ipcc@95598";

        Pkcs12Manager manager = new Pkcs12Manager(new File(filename), pass);
        String expiration = manager.getExpiration(alias);

        String sigAlgName = manager.getSigAlgName(alias);
        X509CertInfo x509CertInfo = manager.getX509CertInfo(alias);
        manager.updateExpiration(alias,keypass,1);
        X509CertInfo x509CertInfo2= manager.getX509CertInfo(alias);
        System.out.println("start" + expiration);
        System.out.println("签名算法：" + sigAlgName);

    }

}